#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import wraps
from json import loads, dumps
from json.decoder import JSONDecodeError
from demjson import encode

from requests import post, get

from common.read_base_config import ReadBaseConfig
from common.read_user_config import ReadUserConfig

read_base = ReadBaseConfig()
read_user = ReadUserConfig()


class FunctionTools:

    @staticmethod
    def request_processes(func):
        @wraps(func)
        def wraps_method(*args, **kwargs):
            request_method = func.__name__
            url = ''
            client = ''
            params = dict()

            # 获得原始请求的入参
            if args:
                url = args[0]
                params = args[1]
                client = str(args[2]).lower()
            elif kwargs:
                url = kwargs.get('url', None)
                params = kwargs.get('params', None)
                client = str(kwargs.get('client', None)).lower()

            if url[0:7] == 'http://' or url[0:8] == 'https://':
                # 直接使用传入的全链接
                base_url = ''
            else:
                # 获取 Api 的 URL
                base_url = read_base.get('http', "base_url")

            # 组装 Headers
            headers = dict()
            headers['Content-Type'] = 'application/json;charset=UTF8'
            headers['version'] = '2.0.3'
            headers['device'] = 'android'

            # 入参参数统一兼容
            if isinstance(params, str):
                try:
                    # 如果能转成功代表是JSON类型使用
                    loads(params)
                except TypeError:
                    raise ValueError("您传入的[params]有误")
            elif isinstance(params, dict):
                params = dumps(params)
            elif params is None or params == '':
                pass
            else:
                raise ValueError("您传入的[params]有误")

            if client == "inner":
                headers['Auth-Type'] = 'inner'
            elif client in ['app', 'admin', 'store_app', 'store_admin']:
                headers['Authorization'] = FunctionTools.get_login_token(client)
                headers['member-id'] = read_user.get('app', 'member_id')

            # 是否输出到控制台
            is_print_console = read_base.get('configuration', 'is_print_console')
            if str(is_print_console).upper() == 'TRUE':
                is_print_console = True
            else:
                is_print_console = False
            if is_print_console:
                print("Request Method： %s" % str(request_method).upper())
                print("Request URL：" + base_url + url)
                print("Request Headers:" + encode(headers).encode("GBK").decode("unicode_escape"))
                if params:
                    print("Request Data：" + encode(loads(params)).encode("GBK").decode("unicode_escape"))
            # 调用接口
            try:
                if request_method == 'post':
                    result = post(url=base_url + url, data=params, headers=headers, timeout=5)
                elif request_method == 'get':
                    result = get(url=base_url + url, data=params, headers=headers, timeout=5)
                else:
                    raise ValueError('request_method 请求方法错误')
            except ConnectionError or TimeoutError:
                raise AssertionError('接口请求超时')
            result_json = FunctionTools.result_processor(url, result, is_print_console)

            return result_json

        return wraps_method

    @classmethod
    def result_processor(cls, url, result, is_print_console=False):
        """
        :param url: 接口名称
        :param result: 返回值
        :param is_print_console: 是否打印
        :return:
        """
        request_time = result.elapsed.total_seconds()
        try:
            assert request_time <= 15
        except AssertionError:
            if is_print_console:
                print("Request Time：" + str(request_time))
            raise AssertionError("请求响应时间过长！")

        try:
            assert result.status_code == 200
        except AssertionError:
            print("Http Code：" + str(result.status_code))
            print("Result Data：" + str(result.text[:2000]))
            raise AssertionError("请求出错！")

        try:
            result_json = result.json()
            if is_print_console:
                print("Result Data：" + encode(result_json).encode("GBK").decode("unicode_escape"))
            return result_json

        except JSONDecodeError:
            print("Result Data：" + str(result.text[:2000]))

    @classmethod
    def get_login_token(cls, client):
        """
        :param client:
        :return: JWT token
        """
        # store_admin:商户后台,store_app:商家APP,admin:总后台,app:销巴生活
        if client in ['store_admin', 'store_app', 'admin', 'app']:
            token = read_user.get(client, 'token')
            return token
        else:
            raise ("传入的client：" + client + "，在base_config.ini文件[http]未读取到")


class HttpRequest:
    """
    使用范例:
    from common.request import HttpRequest
    data = dict()
    data['key'] = 'value'
    HttpRequest.post(url=self.base_url, params=data, client='app')
    """

    @staticmethod
    @FunctionTools.request_processes
    def post(url="", params=None, client="", **kwargs):
        """
        可使用：销巴生活APP，商户后台，总后台，销巴商家APP，内部调用inner
        :param url: 如果传入的是以HTTP开始的全链接请求，不再拼接BaseUrl
        :param params: 如果使用Json.dumps自动以application/json方式请求；如果类型为dict以from-data请求
        :param client: store_admin:商户后台,store_app:商家APP,admin:总后台,app:销巴生活,inner:内部调用接口
        :return:
        if interface_url[0:7] == 'http://' or interface_url[0:8] == 'https://':
            base_url = ''
        else:
            # 获取api的url
            base_url = read_base.get('http', "base_url")

        # 组装headers
        headers = dict()
        headers['Content-Type'] = 'application/json;charset=UTF8'
        headers['version'] = '2.0.3'
        headers['device'] = 'android'

        # 入参参数统一兼容
        if isinstance(params, str):
            try:
                # 如果能转成功代表是JSON类型使用
                loads(params)
            except TypeError:
                raise ValueError("您传入的[params]有误")
        elif isinstance(params, dict):
            params = dumps(params)
        elif params is None or params == '':
            pass
        else:
            raise ValueError("您传入的[params]有误")

        if client == "inner":
            headers['Auth-Type'] = 'inner'
        elif client in ['app', 'admin', 'store_app', 'store_admin']:
            headers['Authorization'] = FunctionTools.get_login_token(client)
            headers['member-id'] = read_user.get('app', 'member_id')
        if is_print:
            print("@@@Post请求调用")
            print("请求URL：" + base_url + interface_url)
            print("请求头:" + encode(headers).encode("GBK").decode("unicode_escape"))
            print("请求参数:" + encode(params).encode("GBK").decode("unicode_escape"))

        # 调用接口
        result = post(base_url + interface_url, data=params, headers=headers)
        result_json = cls.result_processor(result, is_print)

        return result_json
        """
        pass

    @staticmethod
    @FunctionTools.request_processes
    def get(url="", params=None, client="", **kwargs):
        pass


if __name__ == '__main__':
    test = HttpRequest()
    test.post(url='/taxis/member/addr/get/list', params={}, client='app')
